import { ResizeCanvasCommand } from "../command/canvas.command"
import { CloseModalCommand, ToggleModalCommand } from "../command/modal.command"
import { CloseAndRemoveToolsCommand, PanelToggleCollapseCommand, RegisterToolsCommand, ToggleToolCommand } from "../command/tool.command"
import toolConst from "../constant/tool.const"
import ApplicationData from "../data/ApplicationData"
import SettingsData from "../data/SettingsData"
import ToolsData from "../data/ToolsData"
import { appTypeMin } from "../enum/appType.enum"
import panelLayoutEnum from "../enum/panelLayout.enum"
import { ModalToggledMessage, PanelCollapseMessage, ToolAssetClosedMessage, ToolAssetOpenedMessage, ToolToggledMessage } from "../message/tool.message"
import SymbolList from "../SymbolList"
import funcUtil from "../utils/func.util"
import Logger from "../utils/Logger"
import AnalyticsModule from "./AnalyticsModule"
import Module from "./Module"
export default class ToolsModule extends Module {
  activeToolDurationMap: any
  resizeTimeout: number
  bottomPanelHeight: number
  sidePanelWidth: number
  closeAndRemoveTools: any
  toolsData: any
  onAssetOpened: any
  onAssetClosed: any
  onToggleModal: any
  closeModal: any
  onToggleTool: any
  engine: any
  updateLayoutSize: any
  handlePanelCollapse: any
  analytics: any
  settingsData: any
  appData: any
  adjustCanvasForPanel: any
  resizeCanvas: any
  constructor() {
    super(...arguments),
      (this.name = "tools-module"),
      (this.log = new Logger(this.name)),
      (this.activeToolDurationMap = {}),
      (this.resizeTimeout = 0),
      (this.bottomPanelHeight = 0),
      (this.sidePanelWidth = 0),
      (this.closeAndRemoveTools = async () => {
        await this.closeActiveTool(null), this.toolsData.removeAllTools()
      }),
      (this.onAssetOpened = e => {
        const { openAsset: t, toolPanelLayout: i } = this.toolsData
        this.toolsData.setOpenAsset(e.assetType), i === panelLayoutEnum.BOTTOM_PANEL && !!e.assetType != !!t && this.adjustCanvasForPanel()
      }),
      (this.onAssetClosed = () => {
        const { openAsset: e, toolPanelLayout: t } = this.toolsData
        this.toolsData.setOpenAsset(null), t === panelLayoutEnum.BOTTOM_PANEL && e && this.adjustCanvasForPanel()
      }),
      (this.onToggleModal = async e => {
        this.toggleModal(e.modal, e.open)
      }),
      (this.closeModal = () => {
        this.toolsData.openModal && this.toggleModal(this.toolsData.openModal, !1)
      }),
      (this.onToggleTool = async e => {
        const { tool: t, active: i, open: n } = e,
          s = this.toolsData,
          { activeToolName: r, openModal: o, toolPanelLayout: a, toolOpen: c } = s
        if (!i && t !== r) return
        n || a !== panelLayoutEnum.SIDE_PANEL || this.closePanel()
        const h = s.getActiveTool(),
          u = s.getTool(t),
          p = n && u && u.panel
        if (i && t === r) return void (c && !n ? s.setActiveTool(t, !1) : p && !s.isPanelOpen() && this.openPanel())
        o && this.toggleModal(o, !1)
        let m = null
        h && ((m = h.analytic), await this.closeActiveTool(n ? u : null))
        let g = m
        if (i)
          if (u) {
            u.panel && n && this.openPanel(), (g = u.analytic)
            const { manager: e } = u
            await e.activate(n), s.setActiveTool(t, n)
          } else this.log.error(`Tool not loaded: ${t}`)
        this.trackToolTime(m, g), this.engine.broadcast(new ToolToggledMessage(n, t))
      }),
      (this.updateLayoutSize = () => {
        const e = this.toolsData.toolPanelLayout
        let t = e
        const i = toolConst.isBigWin()
        switch (e) {
          case panelLayoutEnum.NORMAL:
            i || (t = panelLayoutEnum.NARROW)
            break
          case panelLayoutEnum.SIDE_PANEL:
            i || (t = panelLayoutEnum.BOTTOM_PANEL)
            break
          case panelLayoutEnum.NARROW:
            i && (t = panelLayoutEnum.NORMAL)
            break
          case panelLayoutEnum.BOTTOM_PANEL:
            i && (t = panelLayoutEnum.SIDE_PANEL)
        }
        this.toolsData.setToolPanelLayout(t)
      }),
      (this.handlePanelCollapse = async e => {
        const { collapse: t } = e
        this.toolsData.setPanelCollapsed(t),
          t || this.toolsData.toolPanelLayout !== panelLayoutEnum.BOTTOM_PANEL || this.closeModal(),
          this.adjustCanvasForPanel(),
          this.engine.broadcast(new PanelCollapseMessage(t))
      }),
      (this.adjustCanvasForPanel = () => {
        const { toolPanelLayout: e, panelCollapsed: t, openAsset: i, openModal: n } = this.toolsData,
          { sidePanelWidth: s, bottomPanelHeight: r } = this,
          o = e !== panelLayoutEnum.SIDE_PANEL || t ? 0 : -toolConst.minWidth,
          a = o !== s,
          c = e === panelLayoutEnum.BOTTOM_PANEL && i && !n ? -Math.floor((50 * window.innerHeight) / 100) : 0,
          h = c !== r
        window.clearTimeout(this.resizeTimeout)
        const d = a ? o : void 0,
          u = h ? c : void 0,
          p = 0 === d || 0 === u ? 0 : 500
        this.resizeCanvas(funcUtil.addResizeDimensions(d, u, p)), (this.bottomPanelHeight = c), (this.sidePanelWidth = o)
      }),
      (this.resizeCanvas = async e => {
        this.engine.commandBinder.issueCommand(new ResizeCanvasCommand(e))
      })
  }
  async init(e, t) {
    this.engine = t
    await t.getModuleBySymbol(SymbolList.SHOWCASE_ANALYTICS)
    this.analytics = await t.getModule(AnalyticsModule)
    ;[this.settingsData, this.appData] = await Promise.all([t.market.waitForData(SettingsData), t.market.waitForData(ApplicationData)])
    this.toolsData = new ToolsData()
    window.addEventListener("resize", this.updateLayoutSize)
    this.updateLayoutSize()
    this.adjustCanvasForPanel()
    this.bindings.push(
      t.commandBinder.addBinding(ToggleToolCommand, this.onToggleTool),
      t.commandBinder.addBinding(ToggleModalCommand, this.onToggleModal),
      t.commandBinder.addBinding(CloseModalCommand, async () => this.closeModal()),
      t.commandBinder.addBinding(PanelToggleCollapseCommand, this.handlePanelCollapse),
      t.subscribe(ToolAssetOpenedMessage, this.onAssetOpened),
      t.subscribe(ToolAssetClosedMessage, this.onAssetClosed),
      this.toolsData.onToolPanelLayoutChanged(this.adjustCanvasForPanel),
      t.commandBinder.addBinding(CloseAndRemoveToolsCommand, this.closeAndRemoveTools),
      t.commandBinder.addBinding(RegisterToolsCommand, async ({ tools: e }) => this.registerTools(...e))
    )
    t.market.register(this, ToolsData, this.toolsData)
  }
  dispose(e) {
    window.removeEventListener("resize", this.updateLayoutSize), e.market.unregister(this, ToolsData), this.closeActiveTool(null)
  }
  registerTools(...e) {
    e.forEach(e => {
      e.featureFlag && this.bindings.push(this.settingsData.onPropertyChanged(e.featureFlag, () => this.updateEnabledTools()))
    }),
      this.toolsData.addTools(e)
  }
  async closeActiveTool(e) {
    const t = this.toolsData,
      i = t.getActiveTool()
    if (i) {
      const { manager: n } = i
      await n.deactivate(), this.closeModal(), !t.toolOpen || !i.panel || (e && e.panel) || this.closePanel(), e || t.setActiveTool(null)
    }
  }
  closePanel() {
    this.toolsData.setToolPanelLayout(toolConst.isBigWin() ? panelLayoutEnum.NORMAL : panelLayoutEnum.NARROW)
  }
  openPanel() {
    this.toolsData.setToolPanelLayout(toolConst.isBigWin() ? panelLayoutEnum.SIDE_PANEL : panelLayoutEnum.BOTTOM_PANEL)
  }
  toggleModal(e, t) {
    const { openModal: i, toolPanelLayout: n } = this.toolsData
    if ((t && i === e) || (!t && e !== i)) return
    const s = e.toLowerCase(),
      r = this.appData.application === appTypeMin.WORKSHOP ? "workshop_gui" : "showcase_gui"
    this.analytics.track(r, { gui_action: `open_${s}`, opened: t }),
      e && this.analytics.track("modal_shown", { modal: e }),
      this.toolsData.setOpenModal(t ? e : null),
      n === panelLayoutEnum.BOTTOM_PANEL && t !== !!i && this.adjustCanvasForPanel(),
      this.engine.broadcast(new ModalToggledMessage(e, t))
  }
  trackToolTime(e, t) {
    if ((t && e !== t && (this.activeToolDurationMap[t] = Date.now()), e)) {
      this.activeToolDurationMap[e] = Date.now() - this.activeToolDurationMap[e]
      const t = {
        tool: `${e}_session_time`,
        duration: this.activeToolDurationMap[e]
      }
      this.analytics.track("tool_session_time", t)
    }
  }
  updateEnabledTools() {
    const e = this.toolsData.toolsMap
    e.atomic(() => {
      for (const t of e)
        if (t.featureFlag) {
          const e = this.settingsData.tryGetProperty(t.featureFlag, !1)
          t.enabled !== e && ((t.enabled = e), t.commit())
        }
    })
  }
}
